/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2015 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = udp_core.c                                                    */
/*  NOTE      =                                                               */
/*  DATE      = 2017/07/31 by songbb                                          */
/******************************************************************************/

#include <stdio.h>
#include <string.h>
#include <sys/time.h>

#include "frmem.h"
#include "frlog.h"
#include "frsutl.h"
#include "udp_core.h"
#include "module.h"
#include "module_comm.h"
#include "frct_comm.h"
#include "frreport_comm.h"


static char hex_asc[] = "0123456789abcdef";
#define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]


FR_STATIC int __udp_frtime2datetimestr(struct timeval *p_tv, char *p_time, unsigned int ui_time_size) {
    struct tm *p_tm = NULL;

    if (p_tv == NULL || p_time == NULL || ui_time_size <= 1)
        return FR_FAIL;

    p_tm = localtime(&(p_tv->tv_sec));

    snprintf(p_time, ui_time_size, "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
             p_tm->tm_year + 1900, p_tm->tm_mon + 1, p_tm->tm_mday,
             p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec, p_tv->tv_usec);

    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  打印时间
*  ARGS     :  st_timestamp                         (时间戳)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void udp_print_timeval(struct timeval st_timestamp) {
    char arr_buff[64];
    __udp_frtime2datetimestr(&st_timestamp, arr_buff, sizeof(arr_buff));
    printf(":[%s]\n", arr_buff);
}


/*******************************************************************************
*  FUNC     :  格式化成十六进制字符串
*  ARGS     :  *p_inbuff    (输入的字符串)
*           :  i_len        (输入的字符串长度)
*           :  *p_outbuff   (格式化后的十六进制字符串)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void udp_bin_to_hex_string(const char *p_inbuff, int i_len, char *p_outbuff) {
    int i_loop;
    char c;
    int i_used = 0;

    for (i_loop = 0; i_loop < i_len; i_loop++) {
        c = p_inbuff[i_loop];
        p_outbuff[i_used++] = hex_asc_hi(c);
        p_outbuff[i_used++] = hex_asc_lo(c);
    }
}

/*******************************************************************************
*  FUNC     :  按一个字节打印十六进行字符串
*  ARGS     :  *p_buff  (char*字符串)
*           :  i_len   (字符串长度)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void udp_print_hex_string(const char *p_buff, int i_len) {
    int i_loop;

    for (i_loop = 0; i_loop < i_len; i_loop++)
        printf("%02x", p_buff[i_loop] & 0xFF);
}

/*******************************************************************************
*  FUNC     :  判断是否需要做udp
*  ARGS     :  p_st_conn                    输入数据信息
*           :  p_st_data_in                 输入数据
*  RTN      :  APM_L7_IS_NO                 不做
*           :  APM_L7_IS_YES                做
*  NOTE     :
*******************************************************************************/
int udp_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet) {
    UDP_PRINT_INFO("udp_detect...\n");
    return APM_L7_IS_YES;
}

/*******************************************************************************
*  FUNC     :  udp的packet解析
*  ARGS     :  p_st_conn(入力链接信息)
            :  p_st_packet(入力packet信息)
            :  p_st_hash_report(保存Frreport_data)
*  RTN      :  FR_FAIL          (失败)
*           :  FR_SUCC          (成功)
*  NOTE     :
*******************************************************************************/
int udp_analysis(Conntrack *p_st_conn, Apm_packet *p_st_analyze_in, Frhash_header *p_st_hash_report) {
    UDP_PRINT_TIMEVAL("PacketIn", p_st_analyze_in->st_timestamp);

    if (p_st_conn == NULL || p_st_analyze_in == NULL || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    if (p_st_analyze_in->ui_payload_len == 0) {
        UDP_PRINT("### i_analyze_ret todo:[%d]\n\n", APM_L7_ANALYZE_TODO);
        return APM_L7_ANALYZE_TODO;
    }

    /*
    * 如果入力p_st_analyze_in是FIN包, 说明本次connection结束,
    * 释放本次session信息. 如果入力p_st_analyze_in是SYN包,说明新的
    * connection开始了, 释放上次可能残留的session信息
    */
    if (p_st_analyze_in->em_analyz_cmd == FRANALYZ_CMD_FIN || p_st_analyze_in->em_analyz_cmd == FRANALYZ_CMD_SYN) {
        if (p_st_analyze_in->em_analyz_cmd == FRANALYZ_CMD_SYN)
            UDP_PRINT_INFO("SYN PACKET\n");
        else if (p_st_analyze_in->em_analyz_cmd == FRANALYZ_CMD_FIN)
            UDP_PRINT_INFO("FIN PACKET\n");
        UDP_PRINT("### i_analyze_ret:[%d]\n\n", APM_L7_ANALYZE_SUCC);
        return APM_L7_ANALYZE_SUCC;
    }


    int i_analyze_ret = 0;
    L7_session *p_st_session = frct_get_session(p_st_conn);
    Frreport_body_data *p_st_body = NULL;
    Frreport_data *p_st_report_data = NULL;

    if (frcap_set_cs_srv(p_st_conn, p_st_analyze_in->dst_ip, p_st_analyze_in->dst_port) != FR_SUCC)
        goto udp_analyze_fail;

    if (p_st_session->arr_session_id[0] == '\0') {
        fruuid(p_st_session->arr_session_id);
    }

    // 上报Request
    if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_SESSION_ID, p_st_session->arr_session_id) != FR_SUCC)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_connInfo(p_st_body, p_st_conn) != FR_SUCC)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_ID, frct_seq_increase(p_st_conn)) != FR_SUCC)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_REQ_ISRESPREQUIRED, FR_NO) != FR_SUCC)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_START_TIMESTAMP, &(p_st_analyze_in->st_timestamp)) !=
        FR_SUCC)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_timeval(p_st_body, APM_REPORT_KEY_REQ_END_TIMESTAMP, &(p_st_analyze_in->st_timestamp)) !=
        FR_SUCC)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_SEND_TIME_US, 0) != FR_SUCC)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_analyze_in->ui_payload_len) != FR_SUCC)
        goto udp_analyze_fail;
    if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, "udp request") != FR_SUCC)
        goto udp_analyze_fail;

    if ((p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ)) == NULL)
        goto udp_analyze_fail;

    if (frreport_data_add_body(p_st_report_data, p_st_body) != FR_SUCC)
        goto udp_analyze_fail;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) != FR_SUCC)
        goto udp_analyze_fail;
    i_analyze_ret = APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);


    UDP_PRINT("### i_analyze_ret success:[%d]\n\n", i_analyze_ret);
    return i_analyze_ret;
udp_analyze_fail:
    frreport_body_free(&p_st_body);
    frreport_data_free(&p_st_report_data);
    UDP_PRINT_EMERG("### i_analyze_ret fail:[%d]\n\n", APM_L7_ANALYZE_FAIL);
    return APM_L7_ANALYZE_FAIL;
}


/*******************************************************************************
*  FUNC     :  释放UDP private数据
*  ARGS     :  *p_st_session_private_in                 (RTP的私有信息)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int udp_session_destroy(void *p_st_session_private_in) {
    UDP_PRINT_INFO("udp_session_destroy\n");
    return FR_SUCC;
}
